﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web;
using System.Web.Routing;
using System.Linq.Expressions;
using System.Configuration;
using System.IO;
using System.Xml;
using RedSand.Web.Config;

namespace RedSand.Web.Language
{
    public class Language
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public string FilePath { get; set; }
        public string Filename { get; set; }
    }
    public static class RsLanguage
    {
        /// <summary>
        /// Mã ngôn ngữ
        /// </summary>
        public static string LanguageCode
        {
            get
            {
                var code = HttpContext.Current.Request.QueryString["Language"];
                code = code ?? (string)HttpContext.Current.Request.RequestContext.RouteData.Values["Language"];
                code = code ?? ConfigurationManager.AppSettings["Language"];
                code = code ?? (string)HttpContext.Current.Session[RsSessionKey.LanguageCode];
                if (string.IsNullOrWhiteSpace(code) || code == "auto")
                {
                    System.Net.WebClient MyWebClient = new System.Net.WebClient();
                    string country = MyWebClient.DownloadString("http://j.maxmind.com/app/geoip.js");
                    country = country.Substring(country.IndexOf("'"));
                    country = country.Remove(country.IndexOf("'"));
                    code = GetLanguageCodeForCountry(country);
                    HttpContext.Current.Session[RsSessionKey.LanguageCode] = code;
                }
                return code.ToLower().Trim();
            }
            set
            {
                HttpContext.Current.Session[RsSessionKey.LanguageCode] = value;
            }
        }
        
        /// <summary>
        /// Lấy đường dẫn file ngôn ngữ tương ứng mã ngôn ngữ
        /// </summary>
        /// <param name="languageCode">Mã ngôn ngữ</param>
        /// <param name="type">Loại file</param>
        /// <returns></returns>
        public static string GetLanguagePath(string languageCode)
        {
            string[] codes = languageCode.Split(new[] { ',' });
            foreach (string code in codes)
            {
                IEnumerable<Language> langs = Languages.Where(item => item.Code == code.Trim());
                if (langs != null && langs.Count() > 0) return langs.First().FilePath;
            }
            throw new Exception("Not found language file!");
        }

        /// <summary>
        /// Lấy mã ngôn ngữ dựa theo mã quốc gia
        /// </summary>
        /// <param name="countryCode">Mã quốc gia</param>
        /// <returns></returns>
        public static string GetLanguageCodeForCountry(string countryCode)
        {
            countryCode = countryCode.Trim().ToLower();
            switch (countryCode)
            {
                case "af": return "fa, ps";
                case "ax": return "sv";
                case "al": return "sq";
                case "dz": return "ar";
                case "as": return "sm";
                case "ad": return "ca";
                case "ao": return "pt";
                case "ai": return "en";
                case "aq": return "en, fr, es, no, nn";
                case "ag": return "en";
                case "ar": return "es";
                case "am": return "hy";
                case "aw": return "nl";
                case "ac": return "en";
                case "au": return "en";
                case "at": return "de";
                case "az": return "az";
                case "bs": return "en";
                case "bh": return "ar";
                case "bd": return "bn";
                case "bb": return "en";
                case "by": return "be";
                case "be": return "de, fr, nl, wa";
                case "bz": return "en";
                case "bj": return "fr";
                case "bm": return "en";
                case "bt": return "dz";
                case "bo": return "es";
                case "ba": return "bs";
                case "bw": return "en";
                case "bv": return "-";
                case "br": return "pt";
                case "io": return "en";
                case "bn": return "ms";
                case "bg": return "bg";
                case "bf": return "fr";
                case "bi": return "fr";
                case "kh": return "km";
                case "cm": return "en, fr";
                case "ca": return "en, fr";
                case "cv": return "pt";
                case "ky": return "en";
                case "cf": return "fr";
                case "td": return "fr, ar";
                case "cl": return "es";
                case "cn": return "zh";
                case "cx": return "en";
                case "cc": return "ms, en";
                case "co": return "es";
                case "km": return "ar, fr";
                case "cg": return "fr";
                case "cd": return "fr";
                case "ck": return "en, mi";
                case "cr": return "es";
                case "ci": return "fr";
                case "hr": return "hr";
                case "cu": return "es";
                case "cy": return "el, tr";
                case "cz": return "cs";
                case "dk": return "da, en";
                case "dj": return "fr, ar";
                case "dm": return "en";
                case "do": return "es";
                case "ec": return "es";
                case "eg": return "ar";
                case "sv": return "es";
                case "gq": return "es, fr";
                case "er": return "ti";
                case "ee": return "et";
                case "et": return "am, ti";
                case "eu": return "cs, da, nl, en, et, fi, fr, de, el, hu, it, lv, lt, mt, pl, pt, sk, sl, es, sv";
                case "fk": return "en";
                case "fo": return "fo";
                case "fj": return "en, fj";
                case "fi": return "fi, sv";
                case "fr": return "br, fr, oc";
                case "gf": return "fr";
                case "pf": return "fr";
                case "tf": return "fr";
                case "ga": return "fr";
                case "gm": return "en, wo, ff";
                case "ge": return "ka";
                case "de": return "de";
                case "gh": return "en";
                case "gi": return "en, es, it, pt";
                case "gr": return "el";
                case "gl": return "kl";
                case "gd": return "en";
                case "gp": return "fr";
                case "gu": return "en, ch";
                case "gt": return "es";
                case "gg": return "en, fr";
                case "gn": return "fr";
                case "gw": return "pt";
                case "gy": return "en";
                case "ht": return "fr";
                case "hm": return "-";
                case "va": return "it, la";
                case "hn": return "es";
                case "hk": return "en, zh";
                case "hu": return "hu";
                case "is": return "is";
                case "in": return "ar, bn, en, hi, mr, ta, te";
                case "id": return "id";
                case "ir": return "fa";
                case "iq": return "ar";
                case "ie": return "en, ga";
                case "im": return "en, gv";
                case "il": return "he";
                case "it": return "it";
                case "jm": return "en";
                case "jp": return "ja";
                case "je": return "en, pt";
                case "jo": return "ar";
                case "kz": return "kk, ru";
                case "ke": return "en";
                case "ki": return "en";
                case "kp": return "ko";
                case "kr": return "ko";
                case "kw": return "ar";
                case "kg": return "ky, ru";
                case "la": return "lo";
                case "lv": return "lv";
                case "lb": return "ar";
                case "ls": return "st, en, zu, xh";
                case "lr": return "en";
                case "ly": return "ar";
                case "li": return "de";
                case "lt": return "lt";
                case "lu": return "de, fr";
                case "mo": return "zh";
                case "mk": return "mk";
                case "mg": return "fr, mg";
                case "mw": return "ny";
                case "my": return "ms";
                case "mv": return "dv";
                case "ml": return "fr, bm";
                case "mt": return "mt";
                case "mh": return "mh";
                case "mq": return "fr";
                case "mr": return "ar";
                case "mu": return "en, fr";
                case "yt": return "fr";
                case "mx": return "es";
                case "fm": return "en";
                case "md": return "mo, ru";
                case "mc": return "fr, it, en";
                case "mn": return "mn";
                case "me": return "sr";
                case "ms": return "en";
                case "ma": return "ar";
                case "mz": return "pt";
                case "mm": return "my";
                case "na": return "en, af, de";
                case "nr": return "na, en";
                case "np": return "ne, en";
                case "nl": return "nl";
                case "an": return "nl";
                case "nc": return "fr";
                case "nz": return "en, mi";
                case "ni": return "es";
                case "ne": return "fr";
                case "ng": return "en, ha, yo, ig, ff";
                case "nu": return "en";
                case "nf": return "en";
                case "mp": return "ch, en";
                case "no": return "nn, no, se";
                case "om": return "ar";
                case "pk": return "ur";
                case "pw": return "en";
                case "ps": return "ar";
                case "pa": return "es";
                case "pg": return "en";
                case "py": return "es";
                case "pe": return "es";
                case "ph": return "en, tl";
                case "pn": return "en";
                case "pl": return "pl";
                case "pt": return "pt";
                case "pr": return "es";
                case "qa": return "ar";
                case "re": return "fr";
                case "ro": return "ro";
                case "ru": return "ru, tt";
                case "rw": return "rw";
                case "bl": return "fr";
                case "sh": return "en";
                case "kn": return "en";
                case "lc": return "en";
                case "pm": return "fr";
                case "vc": return "en";
                case "ws": return "sm, en";
                case "sm": return "it";
                case "st": return "pt";
                case "sa": return "ar";
                case "sn": return "fr, wo";
                case "rs": return "sr";
                case "sc": return "en";
                case "sl": return "en";
                case "sg": return "en, sg, zh";
                case "sk": return "sk";
                case "si": return "sl";
                case "sb": return "en";
                case "so": return "so";
                case "za": return "en, af, zu, xh, tn, st, ss, nr";
                case "gs": return "en";
                case "es": return "ca, es, eu, gl";
                case "lk": return "si, ta";
                case "sd": return "ar";
                case "sr": return "nl";
                case "sj": return "no, ru";
                case "sz": return "en, ss";
                case "se": return "sv";
                case "ch": return "de, fr, it";
                case "sy": return "ar";
                case "tw": return "zh";
                case "tj": return "tg";
                case "tz": return "sw";
                case "th": return "th";
                case "tl": return "pt";
                case "tg": return "fr, ee";
                case "tk": return "en";
                case "to": return "to, en";
                case "tt": return "en";
                case "tn": return "ar";
                case "tr": return "tr";
                case "tm": return "tk";
                case "tc": return "en";
                case "tv": return "tv";
                case "ug": return "en";
                case "ua": return "uk";
                case "ae": return "ar";
                case "gb": return "cy, en, gd, gv, kw";
                case "us": return "en";
                case "um": return "en";
                case "uy": return "es";
                case "uz": return "uz";
                case "vu": return "bi, en";
                case "ve": return "es";
                case "vn": return "vi";
                case "vg": return "en";
                case "vi": return "en";
                case "wf": return "fr";
                case "eh": return "ar";
                case "ye": return "ar";
                case "yu": return "mk, sl, hr";
                case "zm": return "en";
                case "zw": return "en";
                default: return "en";
            }
        }

        /// <summary>
        /// Tất cả  ngôn ngữ
        /// </summary>
        public static List<Language> Languages
        {
            get
            {
                List<Language> list = (List<Language>)HttpContext.Current.Session[RsSessionKey.LanguagesList] ?? new List<Language>();
                if (list.Count == 0)
                {
                    string dir = ConfigurationManager.AppSettings["LanguagesPath"] ?? "/languages";
                    if (Directory.Exists(dir))
                    {
                        IEnumerable<string> paths = Directory.EnumerateFiles(HttpContext.Current.Server.MapPath(dir));
                        foreach (string path in paths)
                        {
                            string filename = Path.GetFileName(path).ToLower();
                            if (Path.GetExtension(path) == ".xml")
                            {
                                try
                                {
                                    XmlDocument doc = new XmlDocument();
                                    doc.Load(path);
                                    XmlNode root = doc.DocumentElement;
                                    if (root != null)
                                    {
                                        XmlAttribute lang = root.Attributes["language"];
                                        XmlAttribute code = root.Attributes["code"];
                                        if (lang != null && code != null)
                                        {
                                            if (code.Value.Length > 2) code.Value = code.Value.Remove(2);
                                            list.Add(new Language { FilePath = path, Name = lang.Value, Code = code.Value.ToLower(), Filename = filename });
                                        }
                                    }
                                }
                                catch { }
                            }
                        }
                    }
                    HttpContext.Current.Session[RsSessionKey.LanguagesList] = list;
                }
                return list;
            }
        }

        /// <summary>
        /// Lấy node gốc của file xml
        /// </summary>
        /// <returns></returns>
        private static XmlNode GetXmlRoot()
        {
            XmlNode root = (XmlNode)HttpContext.Current.Session[RsSessionKey.LanguageXmlRoot];
            if (true)//root == null)
            {
                string file = GetLanguagePath(LanguageCode);
                XmlDocument doc = new XmlDocument();
                doc.Load(file);
                root = doc.DocumentElement;
                HttpContext.Current.Session[RsSessionKey.LanguageXmlRoot] = root;
            }
            return root;
        }

       
        /// <summary>
        /// Chuyển ngôn ngữ từ resource bởi resource-tag
        /// </summary>
        /// <param name="resourceTag">ResourceTag</param>
        /// <returns></returns>
        public static string Translate(string resourceTag)
        {
            return Translate(resourceTag, "Global");
        }

       
        /// <summary>
        /// Chuyển ngôn ngữ từ resource bởi resource-tag
        /// </summary>
        /// <param name="resourceTag">ResourceTag</param>
        /// <param name="resourceGroup">ResourceGroup</param>
        /// <returns></returns>
        public static string Translate(string resourceTag, string resourceGroup)
        {
            resourceGroup = resourceGroup ?? "Global";
            string query = "Group[@name='{0}']/Resource[@tag='{1}']";
            XmlNode root = GetXmlRoot();

            XmlNode child = root.SelectSingleNode(string.Format(query, resourceGroup, resourceTag));
            if (child == null && resourceGroup != "Global")
            {
                child = root.SelectSingleNode(string.Format(query, "Global", resourceTag));
            }
            return child == null ? "[empty]" : child.LastChild.Value;
        }
        
  
    }
}
